package demo.service;

import java.util.Random;
import java.util.concurrent.Future;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
import com.netflix.hystrix.contrib.javanica.command.AsyncResult;
import com.netflix.hystrix.contrib.javanica.conf.HystrixPropertiesManager;

@Service
public class HystrixService {

    private static Logger logger = LoggerFactory.getLogger(HystrixService.class);

    static Random random = new Random();

    /**
     * Synchronous Execution
     * <li>@HystrixCommand注解 该注解对该方法创建了熔断器的功能，并指定了fallbackMethod熔断方法。
     * <li>Its important to remember that Hystrix command and fallback should be placed in the same class and have same
     * method signature (optional parameter for failed execution exception).
     * 
     * @param name
     * @return
     */
    @HystrixCommand(fallbackMethod = "fallback", threadPoolKey = "demo", commandProperties = {
            @HystrixProperty(name = HystrixPropertiesManager.EXECUTION_ISOLATION_STRATEGY, value = "THREAD"),
            @HystrixProperty(name = HystrixPropertiesManager.EXECUTION_ISOLATION_THREAD_TIMEOUT_IN_MILLISECONDS, value = "10000"),
            @HystrixProperty(name = HystrixPropertiesManager.EXECUTION_TIMEOUT_ENABLED, value = "true"),
            @HystrixProperty(name = HystrixPropertiesManager.EXECUTION_ISOLATION_THREAD_INTERRUPT_ON_TIMEOUT, value = "true") },
            // 线程池配置
            threadPoolProperties = { @HystrixProperty(name = HystrixPropertiesManager.CORE_SIZE, value = "2"),
                    @HystrixProperty(name = HystrixPropertiesManager.MAX_QUEUE_SIZE, value = "-1") })
    public String synch(String name) {
        logger.info("synch with {}", name);
        int a = 0;
        int b = 1 / a;
        return "synch with " + name;
    }

    /**
     * Asynchronous Execution
     * 
     */
    @HystrixCommand(fallbackMethod = "fallback", threadPoolKey = "demo", commandProperties = {
            @HystrixProperty(name = HystrixPropertiesManager.EXECUTION_ISOLATION_STRATEGY, value = "THREAD"),
            @HystrixProperty(name = HystrixPropertiesManager.EXECUTION_ISOLATION_THREAD_TIMEOUT_IN_MILLISECONDS, value = "10000"),
            @HystrixProperty(name = HystrixPropertiesManager.EXECUTION_TIMEOUT_ENABLED, value = "true"),
            @HystrixProperty(name = HystrixPropertiesManager.EXECUTION_ISOLATION_THREAD_INTERRUPT_ON_TIMEOUT, value = "true") },
            // 线程池配置
            threadPoolProperties = { @HystrixProperty(name = HystrixPropertiesManager.CORE_SIZE, value = "2"),
                    @HystrixProperty(name = HystrixPropertiesManager.MAX_QUEUE_SIZE, value = "-1") })
    public Future<String> async(final String name) {
        return new AsyncResult<String>() {
            @Override
            public String invoke() {
                logger.info("async with {}", name);
                int a = 0;
                int b = 1 / a;
                return "async with " + name;
            }
        };
    }

    public String fallback(String name) {
        logger.error("fallback with {}", name);
        return "fallback " + name;
    }
}
